"""任务编排器，将工具与 Agent 串联."""

from __future__ import annotations

import json
import logging
from dataclasses import dataclass
from typing import Optional

from ..utils import normalize_symbol, now_shanghai

logger = logging.getLogger(__name__)
from ..quant import QuantAnalyzer
from ..utils import (
    ETFDataTool,
    FeatureEngineeringTool,
    GLOBAL_DATA_STORE,
    WebSearch as WebsiteSearchTool,  # 向后兼容别名
)
from ..workflows import ModelPredictionTool
from . import (
    AgentConfig,
    PredictionAgent,
    PredictionContext,
    QuantAnalysisAgent,
    QuantAnalysisContext,
    RiskControlAgent,
    RiskControlContext,
)


@dataclass
class TaskAgentRunnerConfig:
    agent_config: Optional[AgentConfig] = None


class TaskAgentRunner:
    """封装风险控制、量化分析、预测任务的编排逻辑."""

    def __init__(self, *, config: Optional[TaskAgentRunnerConfig] = None) -> None:
        cfg = config or TaskAgentRunnerConfig()
        agent_cfg = cfg.agent_config
        self._risk_agent = RiskControlAgent(config=agent_cfg)
        self._quant_agent = QuantAnalysisAgent(config=agent_cfg)
        self._prediction_agent = PredictionAgent(config=agent_cfg)

    @staticmethod
    def _default_search_query(fund: str) -> str:
        year = now_shanghai().year
        return f"{fund} ETF 风险 波动 {year}"

    @staticmethod
    def _format_history_summary(payload: dict) -> str:
        reason = payload.get("insufficient_reason")
        reason_text = f"；原因：{reason}" if reason else ""
        metadata = payload.get("metadata", {}) or {}
        requested_limit = payload.get('requested_limit')
        if requested_limit is not None:
            limit_text = f" / 请求条数 {requested_limit}"
        else:
            limit_text = "（全量数据）"
        return (
            f"数据源：{metadata.get('source', 'akshare')}\n"
            f"标准化代码：{payload.get('normalized_symbol')}\n"
            f"数据区间：{payload.get('start_date')} 至 {payload.get('end_date')}\n"
            f"实际条数：{payload.get('actual_count')}{limit_text}{reason_text}"
        )

    def _call_etf_data_tool(self, fund: str) -> dict:
        tool = ETFDataTool()
        output = tool.run({"symbol": fund})
        return json.loads(output)

    def _call_search_tool(self, fund: str) -> dict:
        tool = WebsiteSearchTool()
        query = self._default_search_query(fund)
        result = tool.run(query)
        return json.loads(result)

    def _call_feature_tool(self, symbol: str) -> dict:
        tool = FeatureEngineeringTool()
        result = tool.run({"symbol": symbol, "include_target": True})
        return json.loads(result)

    def run_risk_control(self, fund: str, current_time: str) -> str:
        search_payload = self._call_search_tool(fund)
        data_payload = self._call_etf_data_tool(fund)

        history_summary = self._format_history_summary(data_payload)
        web_sources = json.dumps(search_payload, ensure_ascii=False, indent=2)
        # 风险分析工具已移除，使用空的风险指标
        quant_metrics = json.dumps({}, ensure_ascii=False, indent=2)

        context = RiskControlContext(
            fund=fund,
            current_time=current_time,
            history_summary=history_summary,
            web_sources=web_sources,
            quant_metrics=quant_metrics,
        )
        return self._risk_agent.run(context)

    def run_quant_analysis(
        self,
        fund: str,
        current_time: str,
        risk_report_summary: Optional[str] = None,
    ) -> str:
        normalized = normalize_symbol(fund)
        dataset = GLOBAL_DATA_STORE.get_dataset(normalized)
        if dataset is None:
            raise RuntimeError("未找到缓存的 ETF 数据，请先运行 etf_data_tool")

        # 确保特征数据已生成
        features_df = GLOBAL_DATA_STORE.get_features(normalized)
        if features_df is None:
            self._call_feature_tool(normalized)

        # 调用量化分析器执行实际分析
        quant_analyzer = QuantAnalyzer()
        quant_result = quant_analyzer.analyze(
            symbol=normalized,
            risk_summary=risk_report_summary,
            include_lstm=True,
            enable_optimization=False,
        )
        quant_payload = json.loads(quant_result)

        # 格式化历史数据摘要
        history_summary = self._format_history_summary(
            {
                "normalized_symbol": dataset.symbol,
                "start_date": dataset.start.date().isoformat(),
                "end_date": dataset.end.date().isoformat(),
                "actual_count": dataset.count,
                "requested_limit": None,  # 获取全量数据
                "metadata": {
                    "source": dataset.source,
                },
            }
        )

        # 格式化特征摘要
        features_payload = self._call_feature_tool(dataset.symbol)
        feature_summary = json.dumps(json.loads(features_payload), ensure_ascii=False, indent=2)

        # 格式化量化分析结果摘要
        quant_summary = json.dumps(quant_payload, ensure_ascii=False, indent=2)

        resolved_risk_summary = risk_report_summary
        if resolved_risk_summary is None:
            risk_payload = GLOBAL_DATA_STORE.get_risk_summary(dataset.symbol)
            if risk_payload is not None:
                resolved_risk_summary = json.dumps(risk_payload, ensure_ascii=False, indent=2)
            else:
                resolved_risk_summary = "未提供风险报告摘要，请注意补充。"

        context = QuantAnalysisContext(
            fund=fund,
            current_time=current_time,
            history_summary=history_summary,
            feature_summary=feature_summary,
            risk_summary=resolved_risk_summary,
            quant_result_summary=quant_summary,  # 新增字段
        )
        return self._quant_agent.run(context)

    def run_prediction(
        self,
        fund: str,
        current_time: str,
        position: str,
        latest_quote: str,
        quant_summary: str,
        risk_summary: str,
        technical_snapshot: str,
        model_name: str,
    ) -> str:
        # 调用模型预测工具获取实际预测
        normalized = normalize_symbol(fund)
        prediction_tool = ModelPredictionTool()
        try:
            prediction_result = prediction_tool.run(
                {
                    "symbol": normalized,
                    "model_name": model_name if model_name else None,
                }
            )
            prediction_data = json.loads(prediction_result)
            model_prediction = json.dumps(prediction_data, ensure_ascii=False, indent=2)
        except Exception as e:
            logger.warning(f"模型预测失败: {e}，将使用量化分析摘要")
            model_prediction = "模型预测不可用，请参考量化分析摘要"

        context = PredictionContext(
            fund=fund,
            current_time=current_time,
            position=position,
            latest_quote=latest_quote,
            quant_summary=quant_summary,
            risk_summary=risk_summary,
            technical_snapshot=technical_snapshot,
            model_name=model_name,
            model_prediction=model_prediction,  # 新增字段
        )
        return self._prediction_agent.run(context)

